package personal.jinhui.paprika.service;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.ChatListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;

import personal.jinhui.paprika.PaprikaApplication;
import personal.jinhui.paprika.PaprikaService;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;

import personal.jinhui.paprika.service.aidl.IChat;
import personal.jinhui.paprika.service.aidl.IChatManager;
import personal.jinhui.paprika.service.aidl.IChatListener;
import personal.jinhui.paprika.service.aidl.IMessageListener;
import personal.jinhui.paprika.service.aidl.IRoster;

/**
 * An adapter for smack's ChatManager. This class provides functionnality to
 * handle chats.
 */
public class PaprikaChatManager extends IChatManager.Stub {

	private static final String TAG = "PaprikaChatManager";
	private final ChatManager mAdaptee;
	private final Map<String, PaprikaChat> mChats = new HashMap<String, PaprikaChat>();
	private final PaprikaChatListener mPaprikaChatListener = new PaprikaChatListener();
	private final RemoteCallbackList<IChatListener> mRemoteChatCreationListeners = new RemoteCallbackList<IChatListener>();
	private final PaprikaService mService;
	private final UserInfo mUserInfo;
	private final ChatRosterListener mChatRosterListn = new ChatRosterListener();
	private boolean mIsHistory;
	private String mHistoryPath;

	/**
	 * Constructor.
	 * 
	 * @param chatManager
	 *            the smack ChatManager to adapt
	 * @param service
	 *            the service which runs the chat manager
	 * @param roster
	 *            roster used to get presences changes
	 */
	public PaprikaChatManager(final ChatManager chatManager,
			final UserInfo userInfo, final PaprikaService service,
			final Roster roster) {
		mService = service;
		mUserInfo = userInfo;
		mAdaptee = chatManager;
		roster.addRosterListener(mChatRosterListn);
		mAdaptee.addChatListener(mPaprikaChatListener);
		mIsHistory = PreferenceManager.getDefaultSharedPreferences(
				mService.getBaseContext()).getBoolean("settings_key_history",
				false);
		mHistoryPath = PreferenceManager.getDefaultSharedPreferences(
				mService.getBaseContext()).getString(
				PaprikaApplication.CHAT_HISTORY_KEY, "");
		if ("".equals(mHistoryPath))
			mHistoryPath = "/Android/data/personal.jinhui.paprika/chat/";

	}

	/**
	 * Create a chat session.
	 * 
	 * @param contact
	 *            the contact you want to chat with
	 * @param listener
	 *            listener to use for chat events on this chat session
	 * @return the chat session
	 */
	@Override
	public IChat createChat(Contact contact, IMessageListener listener) {
		String key = StringUtils.parseBareAddress(contact.getJIDWithRes());
		PaprikaChat iChat;
		if (mChats.containsKey(key)) {
			iChat = mChats.get(key);
		} else {
			Log.d(TAG, "createChat locally");
			Chat chat = mAdaptee.createChat(key, null);
			iChat = new PaprikaChat(chat, mUserInfo, mIsHistory, mHistoryPath);
			iChat.addMessageListener(listener);

			// maybe a little problem of thread synchronization
			// if so use an HashTable instead of a HashMap for mChats
			mChats.put(StringUtils.parseBareAddress(chat.getParticipant()),
					iChat);
		}

		return iChat;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void destroyChat(IChat iChat) throws RemoteException {
		// Can't remove it. otherwise we will lose all future message in this
		// chat
		// chat.removeMessageListener(mPaprikaChatListener);
		if (iChat == null)
			return;
		deleteChatNotification(iChat);
		mChats.remove(StringUtils.parseBareAddress(iChat
				.getParticipantJIDWithRes()));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void deleteChatNotification(IChat iChat) {
		try {
			mService.deleteNotification(iChat.getParticipantJIDWithRes()
					.hashCode());
		} catch (RemoteException e) {
			Log.v(TAG, "Remote exception ", e);
		}
	}

	@Override
	public PaprikaChat getChat(Contact contact) {
		return mChats
				.get(StringUtils.parseBareAddress(contact.getJIDWithRes()));
	}

	/**
	 * {@inheritDoc}
	 */

	@Override
	public void addChatListener(IChatListener listener) throws RemoteException {
		if (listener != null)
			mRemoteChatCreationListeners.register(listener);
	}

	@Override
	public void removeChatListener(IChatListener listener)
			throws RemoteException {
		if (listener != null)
			mRemoteChatCreationListeners.unregister(listener);
	}

	/**
	 * A listener for all the chat creation event that happens on the
	 * connection.
	 * 
	 * @author darisk
	 */
	private class PaprikaChatListener extends IMessageListener.Stub implements
			ChatListener {

		/**
		 * Constructor.
		 */
		public PaprikaChatListener() {
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void chatCreated(Chat chat, boolean locally) {
			Log.d(TAG, "Chat" + chat.toString() + " created locally " + locally
					+ " with " + chat.getParticipant());
			// we already have created ichat in chatactivity maually if locally
			// here we only create a new ichat when chat is initiated from
			// outside
			if (!locally) {
				PaprikaChat iChat = new PaprikaChat(chat, mUserInfo,
						mIsHistory, mHistoryPath);
				mChats.put(StringUtils.parseBareAddress(chat.getParticipant()),
						iChat);
				iChat.addMessageListener(mPaprikaChatListener);
			}
			try {
				final int n = mRemoteChatCreationListeners.beginBroadcast();

				for (int i = 0; i < n; i++) {
					IChatListener listener = mRemoteChatCreationListeners
							.getBroadcastItem(i);
					listener.onChatCreated(mChats.get(StringUtils
							.parseBareAddress(chat.getParticipant())), locally);
				}
				mRemoteChatCreationListeners.finishBroadcast();
			} catch (RemoteException e) {
				// The RemoteCallbackList will take care of removing the
				// dead listeners.
				Log.w(TAG,
						" Error while triggering remote connection listeners in chat creation",
						e);
			}
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void processMessage(final IChat iChat, Message message) {

			String body = message.getBody();
			Log.d("#########", "333 processMessage, IChat, msg body is " + body);

			try {
				final int n = mRemoteChatCreationListeners.beginBroadcast();

				for (int i = 0; i < n; i++) {
					IChatListener listener = mRemoteChatCreationListeners
							.getBroadcastItem(i);
					listener.onProcessMessage(iChat, message);
				}
				mRemoteChatCreationListeners.finishBroadcast();
			} catch (RemoteException e) {
				// The RemoteCallbackList will take care of removing the
				// dead listeners.
				Log.w(TAG,
						" Error while triggering remote connection listeners in chat creation",
						e);
			}
		}

		@Override
		public void stateChanged(final IChat iChat) {
		}
	}

	/**
	 * implement a roster listener, is used to detect and close otr chats.
	 * 
	 */
	private class ChatRosterListener implements RosterListener {

		@Override
		public void entriesAdded(Collection<String> arg0) {
		}

		@Override
		public void entriesDeleted(Collection<String> arg0) {
		}

		@Override
		public void entriesUpdated(Collection<String> arg0) {
		}

		@Override
		public void presenceChanged(Presence presence) {
			if (!mChats.containsKey(StringUtils.parseBareAddress(presence
					.getFrom()))) {
				return;
			}
		}
	}
}
